package com.xt.base.wireless.server.socket;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.xt.base.exception.SystemError;
import com.xt.base.reflection.BaseReflector;
import com.xt.base.util.DateUtils;
import com.xt.base.util.SpringUtil;
import com.xt.base.wireless.server.MobileActionUtil;
import com.xt.base.wireless.util.ByteCoding;

/**
 * <br>
 * <br>
 * 
 * <p>
 * <a href=".java.html"><i>查看源文件</i></a>
 * </p>
 * 
 * @author 杨洪波
 * @create-date:2010-9-12
 */
public class SocketServerThread extends Thread {
	Logger log = Logger.getLogger(getClass());
	
	private Socket sc = null;
	private long clientNum = 0;
	private InputStream is;
	private OutputStream os;
	
	private FileOutputStream fos = null;  
	//private RandomAccessFile raf = null;
	private int len=0,size=10*1024;
	private byte[] bytes = null;
	private String tmpPath = "tempFiles/";
	
	/**当前socket连接最后活跃时间。与当前时间之差即为空闲时间。*/
	private long idleTime;
	/** 当前连接是否坏死 */
	private boolean isBaded = false;
	
	private File tmpBigFile;
	private String basePath;

	public SocketServerThread(Socket socket, long num) { // 构造函数
		this.sc = socket; // 初始化socket变量
		clientNum = num; // 初始化clientnum变量
		idleTime = new Date().getTime();
		log.info("服务器端地址："+sc.getLocalSocketAddress());
		log.info("客户端地址："+sc.getRemoteSocketAddress());
		basePath = this.getClass().getClassLoader()
		.getResource("").getPath();
		basePath = basePath.substring(0, basePath.indexOf("WEB-INF"))+tmpPath;;
		log.info("SocketServerThread::basePath="+basePath);
	}
	
	/**
	 * 如果连接空闲时间超过配置时间，即允许关闭
	 * @param idlePeriod
	 * @return
	 */
	public boolean isIdleClosed(long idlePeriod){
		boolean bool = false;
		
		if(idlePeriod<=(new Date().getTime()-idleTime)){
			bool = true;
		}
		return bool;
	}
	
	public void close(){
		try {
			if (is != null) is.close();
			if (os != null) os.close();
			if (sc != null) sc.close();
		} catch (IOException e) {
			throw new RuntimeException("关闭ServerThread中的连接时抛出异常",e);
		}
	}
	
	public  boolean isBaded(){
		return this.isBaded;
	}

	public void run() { // 线程主体
		try {// 在这里实现数据的接受和发送
			log.info("第" + clientNum + "个客户端已连接；接受缓冲区大小："+sc.getReceiveBufferSize());
			//设置接受数据的缓冲区大小
			sc.setReceiveBufferSize(size);
			log.info("修改接受缓冲区大小为："+sc.getReceiveBufferSize());
			log.info("默认发送数据缓冲区大小："+sc.getSendBufferSize());
			sc.setSendBufferSize(size);
			log.info("修改发送数据缓冲区大小："+sc.getSendBufferSize());
			is = sc.getInputStream();
			os = sc.getOutputStream();
			String xml = null;
			int pkgHeadSize = 0;
			while(true){
				pkgHeadSize = ByteCoding.decode4Byte(is);
				/*如果出现有废弃包，则读取出来扔掉*/
				if((pkgHeadSize<=0||pkgHeadSize>size)&&isValidPkg){
					if(bytes==null){
						bytes = new byte[size];
					}
					log.info(">>>把当前缓存中剩余的内容读出来， 可能丢弃的字节长度len="+(size));
					is.read(bytes);
					log.info(">>>把当前缓存中剩余的内容读出来， 已丢弃的字节长度len="+(size));
					isValidPkg = false;
					continue;
				}
				xml =ByteCoding.decodeBytes2String(is, pkgHeadSize);
				/*if(xml==null || "".equals(xml)){
					continue;
				}else*/ if("connectionIsBaded".equals(xml)){
					this.isBaded = true;
					break;
				}
				log.info("接收到第" + clientNum + "个客户端的信息，信息长度为："+xml.length());
				this.execute(xml);
				idleTime = new Date().getTime();
				
			}
			log.info("第"+ clientNum +"个线程已经退出监听状态！");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			isBaded = true;
			try {
				if (is != null) is.close();
				if (is != null) os.close();
				if (is != null) sc.close();
			} catch (Exception e) {
				log.error("关闭连接时出错",e);
			}
		}
		
	}
	
	private void send(Map<String,Object> map){
		log.info("SocketServerThread.send::map="+map);
		String message = MobileActionUtil.parseResultMap2Xml(map);
		try {
			byte[] bs = ByteCoding.encodeString2Bytes(message);
			os.write(bs);
			os.flush();
		} catch (IOException ioe) {
			isBaded = true;
			ioe.printStackTrace();
		}
	}
	
	public void execute(String xml){
		Map<String,Object> map = MobileActionUtil.parseRequestXml(xml);
		if("bigFileUpload".equals(map.get("accessDataType"))){
			bigFileUpload(map);
		}else if("bigFileDownload".equals(map.get("accessDataType"))){
			bigFileDownload(map);
		}else {
			simpleAccess(map);
		}
	}
	
	@SuppressWarnings("unchecked")
	public void simpleAccess(Map<String,Object> map){
		if(map.get("action")==null){
			throw new SystemError(new Object(),new Object[]{map},"没有指定Action！");
		}
		if(map.get("method")==null){
			throw new SystemError(new Object(),new Object[]{map},"没有指定Method！");
		}
		Object o = null;
		try{
			o = SpringUtil.getWebBean(String.valueOf(map.get("action")));
		}catch(Exception e){
			isBaded = true;
			e.printStackTrace();
			throw new SystemError(this,new Object[]{},"指定的Action不正确，或者没有为Spring配置Action！");
		}
		try{
			o = BaseReflector.invoke(o, String.valueOf(map.get("method")), map, Map.class);
		}catch(Exception e){
			isBaded = true;
			e.printStackTrace();
			throw new SystemError(this,new Object[]{},"指定的Method不正确，或者Method的参数类型不匹配！");
		}
		if(o!=null && o instanceof Map<?,?>){//有具体返回值时，才需要解析为xml文件，并处理回调。
			this.send((Map<String,Object>)o);
			log.info("MOA服务器端已响应手机端的请求，返回结果集");
		}else{
			log.info("MOA服务器端已响应手机端的请求，无返回结果集");
		}
	}
	
	private boolean isValidPkg = true;
	private int pkgBodySize = 0,pkgBodyCount=0;
	public void bigFileUpload(Map<String,Object> map){
		log.info("SocketServerThread.bigFileUpload::map="+map);
		try {
			if("complete".equals(map.get("uploadStat"))){
				log.info("SocketServerThread.bigFileUpload::is complete.");
				
				if(fos!=null){
					fos.close();
					fos = null;
				}
				map.put("file", tmpBigFile);
				simpleAccess(map);
				tmpBigFile.delete();
				this.isBaded = true;
				return ;
			}
			if (tmpBigFile == null) {// 创建临时文件
				String fileName = (map.get("tmpFileName")==null
						?null:map.get("tmpFileName").toString());
				if(fileName == null){
					fileName = DateUtils.format(new Date(), "yyyyMMddHHmmss");
					fileName += clientNum;
				}
				tmpBigFile = new File(basePath + fileName );
				
				if("true".equals(map.get("pointLoad"))){
					log.info("SocketServerThread.bigFileUpload::tmpBigFile is exist,o="+tmpBigFile);
					Map<String,Object> result = new HashMap<String,Object>();
					if(tmpBigFile.exists()){
						result.put("pointLoad", "true");
					}else{
						tmpBigFile.createNewFile();
						result.put("pointLoad", "false");
					}
					fos = new FileOutputStream(tmpBigFile, true);  
					result.put("tmpFileName", tmpBigFile.getName());
					this.send(result);
					return;
				}else {
					log.info("SocketServerThread.bigFileUpload::tmpBigFile new created.");
					tmpBigFile.createNewFile();
					fos = new FileOutputStream(tmpBigFile, true);
				}

			}else if(fos==null){
				fos = new FileOutputStream(tmpBigFile, true);  
			}

			if(bytes==null){
				bytes = new byte[size];
			}
			pkgBodySize = ByteCoding.decode4Byte(is);
			pkgBodyCount = 0;
			log.info(">>>正在接受大数据文件，本次要接收的总长度："+pkgBodySize);
			isValidPkg = true;
			while ((len = is.read(bytes, 0, size)) > 0) {
				log.info(">>>正在接收大数据文件，本次接收长度："+len);
				fos.write(bytes, 0, len);
				fos.flush();
				pkgBodyCount += len;
				if(pkgBodySize<=pkgBodyCount){
					if(size-pkgBodySize>0){//把当前缓存中剩余的内容读出来，丢弃。
						isValidPkg = false;
						//len = is.read(bytes);
					}
					break;
				}
			}
			log.info("SocketServerThread.bigFileUpload::fos is write");
			
			if(!"complete".equals(map.get("uploadStat"))){
				Map<String,Object> result = new HashMap<String,Object>();
				result.put("tmpFileName", tmpBigFile.getName());
				result.put("success", "true");
				log.info("SocketServerThread.bigFileUpload::一个包上传结束后，响应手机端,map="+result);
				
				this.send(result);
			}
		} catch (Exception e) {
			isBaded = true;
			log.error("MOA在上传大文件时出错，Exc=" + e.getMessage(), e);
		} finally {
			try {
				if(fos!=null){//为了把每次上传到服务器的数据写入磁盘，必须关闭输出流
					fos.close();
					fos = null;
				}
			} catch (Exception e) {
			}
		}
	}
	
	public void bigFileDownload(Map<String,Object> map){
		if(map.get("action")==null){
			throw new SystemError(new Object(),new Object[]{map},"没有指定Action！");
		}
		if(map.get("method")==null){
			throw new SystemError(new Object(),new Object[]{map},"没有指定Method！");
		}
		Object o = null;
		try{
			o = SpringUtil.getWebBean(String.valueOf(map.get("action")));
		}catch(Exception e){
			isBaded = true;
			e.printStackTrace();
			throw new SystemError(this,new Object[]{},"指定的Action不正确，或者没有为Spring配置Action！");
		}
		try{
			o = BaseReflector.invoke(o, String.valueOf(map.get("method")), map, Map.class);
		}catch(Exception e){
			e.printStackTrace();
			throw new SystemError(this,new Object[]{},"指定的Method不正确，或者Method的参数类型不匹配！");
		}
		if(o!=null && o instanceof InputStream){//有具体返回值时，才需要解析为xml文件，并处理回调。
			//this.send((Map<String,Object>)o);
			long filePos = 0L;
			Map<String,Object> resultMap = new HashMap<String,Object>();
			InputStream is = (InputStream)o;
			int len=0,size=1024*500;
			byte[] pkgBody = new byte[size];
			String message = MobileActionUtil.parseResultMap2Xml(resultMap);
			if(!"new".equals(map.get("downloadStat"))){
				filePos = Long.valueOf(String.valueOf(map.get("downloadStat")));
			}
			try {
				byte[] pkgHead = ByteCoding.encodeString2Bytes(message);
				byte[] pkg = new byte[size+4+pkgBody.length];
				byte[] intByte = null;
				is.skip(filePos);
				while ((len = is.read(pkgBody, 0, size)) > 0) {
					intByte = ByteCoding.encode4Byte(len);
					//参数说明：源、源的起始位置、目标、目标的起始位置、要拷贝的长度
					System.arraycopy(pkgHead, 0, pkg, 0, pkgHead.length);
					System.arraycopy(intByte, 0, pkg, pkgHead.length, intByte.length);
			    	System.arraycopy(pkgBody, 0, pkg,(pkgHead.length+intByte.length), len);
					os.write(pkg);
				}
				resultMap = new HashMap<String,Object>();
				resultMap.put("downloadStat", "complete");
				message = MobileActionUtil.parseResultMap2Xml(resultMap);
				os.write(ByteCoding.encodeString2Bytes(message));
			} catch (Exception e) {
				isBaded = true;
				log.info("MOA服务器端在下载大数据文件时，出现异常 Exception="+e.getMessage(),e);
			}
			/*ByteCoding.encodeString2Bytes(s);
			ByteCoding.encodeByteFile2Bytes(byteFile);*/
			
			log.info("MOA服务器端已响应手机端的请求，返回结果集");
		}else{
			log.info("MOA服务器端已响应手机端的请求，无返回结果集");
		}
	}
}
